import {
    ComponentPropsOptions,
    ExtractPropTypes,
    SetupContext,
    defineComponent,
    getCurrentInstance,
    provide,
    inject
} from 'vue';

export function designComponent<PropsOptions extends Readonly<ComponentPropsOptions>,
    Props extends Readonly<ExtractPropTypes<PropsOptions>>,
    Refer>(
    options: {
        name?: string,
        props?: PropsOptions,
        provideRefer?: boolean,
        setup: (props: Props, setupContext: SetupContext) => {
            refer?: Refer,
            render: () => any

        }
    }
) {
    const {setup, provideRefer, ...leftOptions} = options
    return {
        ...defineComponent({
            ...leftOptions,
            setup(props: Props, setupContext: SetupContext) {
                const ctx = getCurrentInstance() as any;

                if (!setup) {
                    console.error('defineComponent:setup is required')
                    return () => null
                }

                const {refer, render} = setup(props, setupContext)
                ctx._refer = refer;
                if (provideRefer) {
                    //provide是个啥？
                    if (!leftOptions.name) {
                        console.error('defineComponent:name is required when provideRefer is true')
                    } else {
                        provide(`@@${leftOptions.name}`, refer)
                    }
                }
                return render;
            }
        } as any),
        use: {
            ref: (refName: string) => {
                const ctx = (getCurrentInstance() as any).ctx;
                return {
                    get value() {
                        return ((ctx as any).$refs[refName]._refer) as Refer | null;
                    }
                }
            },
            inject: (defaultValue?: any) => {
                return inject(`@@${leftOptions.name}`, defaultValue) as Refer;
            }
        }

    }

}


// const Button = designComponent({
//     name: 'pl-button',
//     props: {
//         label: {type: String},
//         age: {type: Number, default: 10},
//         flag: {type: Boolean, default: true}
//     },
//     setup(props) {
//         return {
//             render: () => {
//
//             }
//         }
//     }
//
//
// })